ECS Anywhere を Azure と Google Cloud (GCP) を使って動かしてみた
みなさん、こんにちは!
AWS事業本部の青柳@福岡オフィスです。
Amazon ECS (Elastic Container Service) のワークロードをAWSの外で実行することができる「ECS Anywhere」がリリースされたということで、前回のブログでは「M1 Mac」の仮想マシン (Parallels) を使って試してみました。
このように、デスクトップ仮想環境を使うと「ECS Anywhere」を手軽に試すことができることが分かりました。
しかし、もう少しクラウドっぽいことをしたいなぁ~ということで、禁断(?)の「Microsoft Azure」および「Google Cloud (いわゆるGCP、以下 分かり易さのためGCPと表記します)」で動かすことができるか試してみました。
こんな構成です
前回の「M1 Mac」の時から根本的な構成は変わりません。
Azureの仮想マシンサービス「Azure VM」、GCPの仮想マシンサービス「GCE (Google Compute Engine)」をそれぞれ作成して、AWS Systems Managerの「マネージドインスタンス」として登録することで、Amazon ECSの「Externalインスタンス」として動作させます。
「M1 Mac」の時にも説明しましたが、AWS⇔Azure、AWS⇔GCPの間の通信要件としては「Azure VMおよびGCEからSystems ManagerエンドポイントへのHTTPS通信」のみが必要です。 専用線やVPNは必要なく、インターネット経由で通信を行います。 仮想マシンへのインバウンド通信も不要です。
やってみた
ECSクラスターを作成する
最初に、ECSクラスターを作成します。
クラスターテンプレートの選択で「ネットワーキングのみ」を選択します。 ネットワーキングオプションの「VPC」にはチェックを入れません。
Externalインスタンスの登録準備 (アクティベーションコードの払い出し)
作成したECSクラスターの画面で「ECSインスタンス」タブを選択して、「Externalインスタンスの登録」ボタンをクリックします。
今回は、AzureとGCPでそれぞれ1台ずつインスタンスを作成しようと思いますので、「インスタンス数」は「2」としました。
アクティベーションキーが埋め込まれたコマンドラインが生成されました。 ひとまず、コマンドラインをテキストファイル等にコピーしておきます。
Azure仮想マシンインスタンスの作成
Azureの仮想マシンインスタンスを用意します。
今回、Azureの無償試用アカウントを作成して作業を行いました。 (アカウントの作成手順については割愛します)
インスタンスを作成する前に、Azureでは「お約束」となる「リソースグループ」を作成します。
「リソースグループ」とは、Azureの各種リソースをまとめて管理するためのグループであり、リソースは必ずいずれかのリソースグループに所属します。
システムや環境などに応じてリソースグループを作成してリソースをグループ化することで管理がし易くなります。 リソースグループに所属するリソースの一覧を表示できるので、環境を削除する際にリソースの消し忘れ防止にもなります。
リソースグループの名前を適当に付けて作成します。 この時、リージョンの指定も行います。(Azureでは日本国内のリージョンとして「東日本」と「西日本」がありますが、今回はAWS、GCPのリージョン(東京)に合わせて「東日本」を選択しました)
次に、仮想マシンインスタンスを作成します。
本来はネットワーク環境からちゃんと作成した方が良いのですが、今回はリソースグループにデフォルトで作成される仮想ネットワーク (VNet) を利用することにします。(AWSで言うデフォルトVPCのようなものです)
「イメージ」(OSの種類) はデフォルトで選択されている「Ubuntu Server 20.04 LTS」にしました。
インスタンスの「サイズ」は、お試しなので最もリーズナブルな「Standard_D2as_v4」を選びました。
その他のオプションは全てデフォルトのままとしました。
インスタンスが起動したことを確認したので、次に進みます。
GCP仮想マシンインスタンスの作成
今度は、GCPの仮想マシンインスタンスを用意します。
GCPでも無料トライアルのアカウントを作成して作業を行いました。
GCPでは、アカウント内に「プロジェクト」と呼ばれる概念があり、システムや環境に応じてプロジェクトを分けて管理することができます。 (Azureの「リソースグループ」と似ているようで、ちょっと違いますね)
最初から用意されている「My First Project」を使用してもよいのですが、今回は検証用にプロジェクトを作成して作業を行うことにします。
プロジェクトの名前を適当に付けて作成します。 作成した後に、現在のプロジェクトを変更するのを忘れないようにしましょう。(よく忘れる)
GCPでも、本来はネットワーク環境からちゃんと作成した方が良いのですが、今回はアカウントにデフォルトで用意されている仮想ネットワーク (VPC) を利用することにします。
GCPの場合、このタイミングでリージョンを指定しますので「東京リージョン (asia-northeast1)」を選択します。
「マシンタイプ」はデフォルトの「e2-medium」を選びました。
「ブートディスク」(OSの種類) はデフォルトで選択されている「Debian GNU/Linux 10」にしました。
インスタンスが起動したことを確認したので、次に進みます。
Externalインスタンスの登録 (Azure/GCP)
AzureとGCPでそれぞれ仮想マシンのインスタンスを作成しましたので、これらのインスタンスをECSの「Externalインスタンス」として登録します。
それぞれ、インスタンスにSSHで接続して作業を行います。
「M1 Mac」の時にも説明しましたが、生成された「Externalインスタンス登録用のコマンド」はroot権限で実行する必要があるため、そのままコピーペーストするのではなく、少し手を加える必要があります。
AWSマネジメントコンソールに表示されたコマンドラインは、AWSが用意したスクリプトをダウンロードする「curlコマンド」と、ダウンロードしたスクリプトを実行する「bash ecs-anywhere-install.sh」コマンドを「&&」で連結したものになっています。
これを「curlコマンド」と「bash ecs-anywhere-install.sh」に分けて実行し、かつ、後者のbashコマンドには「sudo」を付けて実行します。
$ curl --proto "https" -o "/tmp/ecs-anywhere-install.sh" "https://amazon-ecs-agent.s3.amazonaws.com/ecs-anywhere-install-latest.sh"
$ sudo bash /tmp/ecs-anywhere-install.sh --region "ap-northeast-1" --cluster "ecs-anywhere-test" --activation-id "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" --activation-code "XXXXXXXXXXXXXXXXXXXX"
スクリプトを実行すると、以下の処理が順次行われます。
- APTリポジトリのアップデート
- SSMエージェントのインストール
- SSMエージェントをSystems Managerへ登録
- Dockerのインストール
- ECSエージェントのインストール (Dockerコンテナとしてインストール)
- ECSエージェントの起動
以下のメッセージが表示されれば、インストール処理は正常に完了しています。
########################## This script installed three open source packages that all use Apache License 2.0. You can view their license information here: - ECS Agent https://github.com/aws/amazon-ecs-agent/blob/master/LICENSE - SSM Agent https://github.com/aws/amazon-ssm-agent/blob/master/LICENSE - Docker engine https://github.com/moby/moby/blob/master/LICENSE ##########################
Externalインスタンスが登録されたことの確認
AWSマネジメントコンソールに戻って、ECSクラスター画面の「ECSインスタンス」タブを表示します。
Externalインスタンスが2台、正常に登録されていることが確認できました!
(どちらがAzureでどちらがGCPか区別が付きませんが、、、メモリのスペックで判断すると、上の段がAzure VMのインスタンスであるようです)
ECSサービスを実行してみる
それでは、いよいよ「Azure」と「GCP」の上で「ECS」のサービスを実行してみましょう。
まずは、タスク定義を作成します。
「互換性」の選択は「EXTERNAL」を指定します。
Externalインスタンスでは「ネットワークモード」で選択可能な項目が「bridge」「host」「none」のみとなっています。「awsvpc」は選択することができません。 ここでは「<default>」=「bridge」を選択します。
続いて、コンテナの設定を行います。
「M1 Mac」の時と同様に、今回も必須項目のみ設定していきます。 コンテナイメージはDocker Hub公式リポジトリからnginxを指定します。
ポートマッピングの設定については「M1 Mac」の時と違って「動的ポートマッピング」で指定することにします。(ホストポートを「0」とする)
※ 固定ポートマッピングでも良いのですが、bridgeネットワークを使用しているため、固定ポートマッピングだと1ホストあたり1つしかタスクを起動することができなくなります。
その他の項目はデフォルトのままにして、タスク定義を作成します。
次に、ECSサービスを作成します。
今回は、実行するタスクの数を「10」にしてみます。
ECSサービスを作成したら、正常に起動するかどうか確認しましょう。
タスクが10個、正常に起動していることが確認できました!
見辛いかもしれませんが、2つあるインスタンスそれぞれで5個ずつタスクが起動していることが分かります。
ECSサービスにアクセスしてみる (Azure編)
起動したECSサービスへアクセスしてみましょう。
EXTERNAL起動タイプではロードバランサーを使用することができないため、コンテナが稼働しているホストインスタンスのポートに直接アクセスすることにします。
Azure VMインスタンスにはパケットフィルタ機能が備わっており、デフォルトでは外部からアクセスすることができません。 インターネット経由でポートへアクセスできるように設定を行います。
インスタンスの設定から「ネットワーク」-「受信ポートの規則を追加する」を選択して、設定します。
「ソース」で「IP Addresses」を選択して、アクセス元 (自宅・職場) のグローバルIPアドレスを指定します。
「宛先ポート範囲」には「80」を指定、、、したいところですが、今回「動的ポートマッピング」を使用しているため、動的ポートマッピングで使われるエフェメラルポートの範囲 (49153-65535) を指定する必要があります。
ポートへアクセスできるようにしましたので、インスタンスの「グローバルIPアドレス」と「ポート番号」を確認してアクセスしてみます。
「グローバルIPアドレス」は、Azure VMインスタンスのプロパティから「パブリックIPアドレス」の値を確認します。
「ポート番号」は、Azure VMインスタンス上で稼働しているECSタスクのプロパティを参照して、コンテナの詳細から「ホストポート」を確認します。
確認した「グローバルIPアドレス」と「ポート番号」を使ってブラウザからアクセスしてみると・・・
無事にアクセスすることができました!
ECSサービスにアクセスしてみる (GCP編)
同様にして、GCP側でもアクセスを行ってみます。
GCPのGCEインスタンスでもパケットフィルタの設定を行う必要がありますが、Azure VMがインスタンス自体が持つ「受信ポート規則」の設定であったのに対して、GCEでは「ファイアウォール」と呼ばれるリソースを定義してインスタンスに割り当てる必要があります。(AWSのセキュリティグループに近いと言えば近いですね)
「VPCネットワーク」-「ファイアウォール」を開いて、「ファイアウォールルールの作成」を選択します。
「トラフィックの方向」は「上り」を選択します。(GCPファイアウォールでは「上り=インバウンド」「下り=アウトバウンド」です)
「一致したときのアクション」は「許可」を選択します。
「ターゲットタグ」には任意のタグ名を設定します。 このタグを、ファイアウォールを使いたいインスタンスに対して付与することで、割り当てが行われます。
「ソースIPの範囲」に、アクセス元 (自宅・職場) のグローバルIPアドレスを指定します。
「プロトコルとポート」は、前述したように、動的ポートマッピングで使われるエフェメラルポートの範囲 (49153-65535) を指定します。
こちらも、ポートへアクセスできるようにしましたので、インスタンスの「グローバルIPアドレス」と「ポート番号」を確認してアクセスしてみます。
「グローバルIPアドレス」は、GCEインスタンスのプロパティから「外部IP」の値を確認します。
「ポート番号」は、Azure VMの時と同様に、ECSタスクのプロパティよりコンテナの詳細から「ホストポート」を確認します。
確認した「グローバルIPアドレス」と「ポート番号」を使ってブラウザからアクセスしてみると、こちらも正常にアクセスできることが確認できました!
後片付け (Externalインスタンスの登録を解除する)
検証が終わったら、Externalインスタンスとして登録したインスタンスをECSから「登録解除」します。
ECSインスタンスの一覧画面で、Externalインスタンスの「コンテナインスタンス」(のID) をクリックするとプロパティ画面になりますので、右上の「登録解除」ボタンをクリックします。
「AWS Systems Managerから登録解除」にチェックを入れて、登録解除します。
ECSおよびSystems Managerから登録解除した後は、下記ドキュメントの記述に従って、インストールしたECS/SSM関連コンポーネントの停止とアンインストールを行うことができます。
Deregistering an external instance - Amazon Elastic Container Service
ただ、インスタンスを削除してしまうのであれば、これらの手順は省略可能かと思います。
補足: ECS Anywhereの「ロードバランサー」について
実際にECS Anywhereの環境を構築してみて分かったのですが、ECS Anywhereにおけるタスク定義 (互換性「EXTERNAL」を指定) では「Auto Scaling」と「ネットワーク構成 (特にロードバランサーとの連係)」を設定することができません。
これらのうち、Auto Scaling (インスタンスのAuto ScalingではなくタスクのAuto Scaling) については実装することも技術的に可能なのではないか?と思っているのですが、ロードバランサーについては難しいのではないかと考えています。
EC2インスタンスを利用する場合には、ECSとElastic Load Balancerが密接に連係することで動作しています。 一方、ECS Anywhere (Externalインスタンス) がロードバランサーに対応するためには、AWSがオンプレミスのロードバランサーを細かくコントロールする必要があります。
特に、今回のように「動的ポートマッピング」を使用した場合は、コンテナインスタンス上でタスクが起動するたびに動的に生成されるエフェメラルポートを、都度ロードバランサーに登録していく必要があるはずです。(もちろん、タスクが終了した場合はポートの解除も発生します)
もしかすると、高機能なロードバランサーであればそのようなことが可能なのかもしれませんが、オンプレミスの多様なロードバランサーのベンダー・機種に対応するのは難しいのではないかと思います。
そういう訳で、ECS Anywhereによって提供されるオンプレミスのサーバーを用いたワークロードは、現時点では以下のような用途に限定されるのではないかと思います。
- 向いていない
- インターネットに対するWebサービス提供
- イントラネットに対するWebサービス提供
- 向いている
- 分散バッチ処理
- (キューイングとの組み合わせによる) ワーカー処理
元々、AWS内で完結したサービスとしてのECSを利用することは「拡張性」「伸縮自在性」「インフラ運用管理のオフロード」etc. などの利点を最大限に享受できる訳ですが、敢えてオンプレミスの資産を使って「ECS Anywhere」を利用する理由や目的があるとすれば、それは以下のようなものだと思われます。
- 企業のコンプライアンス要件のためにデータをクラウド上に置けない
- クラウド移行などによって余剰となったオンプレミス資源の有効活用
このようなシチュエーションであれば、上記で「向いている」に挙げたような処理は、これらの理由・目的と実は親和性があるのでは?という気もします。
(「いや、そうじゃない」というご意見があれば、是非教えてください)
おわりに
M1 Macに続き、調子に乗って(?) AzureとGCPでECS Anywhereを動かすことにチャレンジしてみましたが、意外にアッサリと動作させることができました。
実のところ、ECSの部分よりも、久しぶりに触ったAzureやGCPの操作や機能に手こずったというオチでした。(笑)
検証することでいろいろ見えてきた (まだ見えていない) ことも出てきましたので、引き続きECS Anywhereを触ってみたいと思います。